//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   ifdiv
//File Name     :   float_table.v
//Module name   :   float_table
//Full name     :   float number table 
//
//Author        :   xiang tian
//Email         :   
//Data          :   2020/5/13
//Version       :   V1.01
//
//Abstract      :   Read an Lut Table,calc rcp mantissa & exponent
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//1.01: add float monitor, add busy port
//
//-----------------------------------------------------------------------------

//-----------------------------
//DEFINE MACRO
//-----------------------------
module float_rcp(
    clk,
    rst_n,
    busy,
    en,
    sign,
    exp,
    man,
    iszero,
    isinf,
    isnan,
    sign_rcp,
    man_ff,
    man_rcp,
    exp_rcp,
    iszero_rcp,
    isinf_rcp,
    isnan_rcp,
    valid
);

`include "float_monitor_func.v"


input              clk;
input              rst_n;
input              busy;
input              en;
input              sign;
input  [8:0]       exp;
input  [30:0]      man;
input              iszero;
input              isinf;
input              isnan;
output reg         sign_rcp;
output reg [24:0]  man_ff;
output reg [24:0]  man_rcp;
output reg [8:0]   exp_rcp;
output reg         iszero_rcp;
output reg         isinf_rcp;
output reg         isnan_rcp;
output reg         valid;    


wire [4:0]  sel;
wire [19:0] dout;
wire [13:0] delta;
wire [5:0]  k;
wire [24:0] rcp_man_inter;
wire [8:0]  rcp_exp_inter;

wire [25:0] man_inter = man[30:5];
wire [26:0] one_shift_x2 = 27'h400_0000;
wire [26:0] one_minus_delta_x2 = one_shift_x2 - (delta<<12);
wire [32:0] k_times_man_x2 = k * man_inter;
wire [26:0] rcp_man_x2 = one_minus_delta_x2 - (k_times_man_x2>>6);

assign sel   = man[30:26];
assign delta = dout[19:6];
assign k     = dout[5:0];



assign rcp_man_inter = rcp_man_x2[24:0];
assign rcp_exp_inter = (man[30:6]==25'b0) ? (~exp+1'b1) : (~exp);


//only for debug
always @(posedge clk)
begin
    if(en && rcp_man_x2[26:25]!=2'b01)
    begin
        $display("Wrong floating rcp calculation!\n");
        $display("AT time %t, in module %M\n",$time);
        $stop;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        sign_rcp  <= 0;
        man_ff    <= 0;
        exp_rcp   <= 0;
        iszero_rcp<= 0;
        isinf_rcp <= 0;
        isnan_rcp <= 0;
        man_rcp   <= 0;
    end
    else if(en && !busy)
    begin
        sign_rcp   <= sign  ;
        man_ff    <= man[30:6]   ;
        man_rcp   <= (man[30:6]==25'b0) ? 25'b0: rcp_man_inter;
        iszero_rcp<= iszero;
        isinf_rcp <= isinf ;
        isnan_rcp <= isnan ;
        exp_rcp   <= rcp_exp_inter;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)     valid <= 1'b0;
    else if(!busy) valid <= en;
end
R_rom u_rom_table(
    .clka (clk),
    .addra(sel),
    .douta(dout)
);    


//only for monitor

wire  [31:0] float_monitor;

assign float_monitor = float_asmb(sign_rcp,exp_rcp[7:0],man_rcp[24:2]);

endmodule
